package com.toplabs.unashu.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.toplabs.unashu.common.Constants;
import com.toplabs.unashu.common.response.ResponseStatus;
import com.toplabs.unashu.common.utils.RedisUtils;
import com.toplabs.unashu.exception.ServiceException;
import com.toplabs.unashu.service.AuthService;
import com.toplabs.unashu.vo.AuthTokenVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * @author toplabs
 * @since 2022/08/09
 * <p>This java file was created by toplabs in 2022/08/09.
 * The following is the description information about this file:</p>
 * <p>description:</p>
 */
@Service("authService")
public class AuthServiceImpl implements AuthService {

    @Value("${api.auth.refresh-expires-in}")
    private long refreshExpiresIn;

    private final RedisUtils redisUtils;

    public AuthServiceImpl(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    @Override
    public AuthTokenVO authorization(String code, String authType) {
        Long userId;
        if (Constants.AUTH_TYPE_REFRESH.equals(authType)) {
            if (!redisUtils.hHasKey(Constants.CACHE_PREFIX_REFRESH_TOKEN, code)) {
                throw new ServiceException(ResponseStatus.REFRESH_TOKEN_TIMEOUT);
            }
            String tokenInfoStr = redisUtils.hGet(Constants.CACHE_PREFIX_REFRESH_TOKEN, code);
            AuthTokenVO tokenInfo = JSONUtil.toBean(tokenInfoStr, AuthTokenVO.class);
            // 判断时间是否过期
            if (DateUtil.date().getTime() >= tokenInfo.getRefreshExpiresIn()) {
                throw new ServiceException(ResponseStatus.REFRESH_TOKEN_TIMEOUT);
            }
            userId = tokenInfo.getUserId();
        } else {
            userId = Long.valueOf(code);
        }
        if (userId == null) {
            throw new ServiceException("user id is empty");
        }
        StpUtil.login(userId);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        AuthTokenVO authTokenVo = new AuthTokenVO();
        authTokenVo.setUserId(userId);
        authTokenVo.setAccessToken(tokenInfo.getTokenValue());
        DateTime now = DateUtil.date();
        authTokenVo.setExpiresIn(DateUtil.offsetSecond(now, Math.toIntExact(tokenInfo.getTokenTimeout())).getTime());

        String refresh = IdUtil.simpleUUID();
        authTokenVo.setRefreshToken(refresh);
        authTokenVo.setRefreshExpiresIn(DateUtil.offsetSecond(now, Math.toIntExact(refreshExpiresIn)).getTime());
        boolean result = redisUtils.hSet(Constants.CACHE_PREFIX_REFRESH_TOKEN, refresh, JSONUtil.toJsonStr(authTokenVo), refreshExpiresIn) &&
                redisUtils.hSet(Constants.CACHE_PREFIX_ACCESS_TOKEN, tokenInfo.getTokenValue(), JSONUtil.toJsonStr(authTokenVo), refreshExpiresIn);
        // 保存redis失败
        if (!result) {
            StpUtil.logout();
            throw new ServiceException("generate token failed");
        }
        return authTokenVo;
    }
}
